﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Runtime.CompilerServices;
using System.Threading;
using MySql.Data.MySqlClient;
using ServiceStack.OrmLite;

namespace Fetches.Process.Utility
{
    public class LowercaseNamingStrategy : OrmLiteNamingStrategyBase
    {
        public override string GetTableName(string name)
        {
            return name.ToLower();
        }

        public override string GetColumnName(string name)
        {
            return name.ToLower();
        }
    }

    public class ConnectionPool
    {
        private const int PoolMaxSize = 20;
        private static DbProviderFactory DbFactory;


        private static readonly Dictionary<string, ConnectionPool> _connPool = new Dictionary<string, ConnectionPool>();

        private readonly Stack<IDbConnection> _pool;

        private string _connectionString;
        private int _currentSize;

        private ConnectionPool()
        {
            if (_pool == null)
                _pool = new Stack<IDbConnection>();
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public static ConnectionPool GetInstance(string connectionStringName = "ConnectionString")
        {
            if (!_connPool.ContainsKey(connectionStringName))
            {
                if (ConfigurationManager.ConnectionStrings[connectionStringName] == null)
                {
                    connectionStringName = "ConnectionString";
                }

                string providerName;
                if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
                    providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
                else
                    throw new Exception("ConnectionStrings中没有配置提供程序ProviderName！");
                var connStr = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
                return GetInstance(providerName, connStr, connectionStringName);
            }

            return _connPool[connectionStringName];
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public static ConnectionPool GetInstance(string providerName, string connectionString,
            string connectonName = "")
        {
            if (string.IsNullOrEmpty(connectonName))
            {
                connectonName = connectionString;
            }

            if (!_connPool.ContainsKey(connectonName))
            {
                _connPool[connectonName] = new ConnectionPool
                {
                    _connectionString = connectionString,
                };
            }

            return _connPool[connectonName];
        }

        public static IDbConnection GetContentConnection()
        {
            return GetInstance("ContentConnection").GetConnection();
        }

        public static void ReturnContentConnection(IDbConnection conn)
        {
            GetInstance("ContentConnection").ReturnConnection(conn);
        }

        public IDbConnection GetConnection()
        {
            IDbConnection conn;
            lock (this)
            {
                if (_pool.Count == 0)
                {
                    if (_currentSize < PoolMaxSize)
                    {
                        conn = CreateConnection();
                        _currentSize++;
                        //把conn加入到pool 中

                        _pool.Push(conn);
                    }
                    else
                    {
                        try
                        {
                            Monitor.Wait(this);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                        }
                    }
                }

                conn = _pool.Pop();

                if (conn.State == ConnectionState.Broken)
                    conn.Close();
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
            }

            return conn;
        }


        public void ReturnConnection(IDbConnection conn)
        {
            lock (this)
            {
                _pool.Push(conn);
                Monitor.Pulse(this);
            }
        }

        private IDbConnection CreateConnection()
        {
            lock (this)
            {
                if (DbFactory == null) DbFactory = new MySqlClientFactory();
                IDbConnection dbConnecttion = DbFactory.CreateConnection();

                if (dbConnecttion != null)
                {
                    dbConnecttion.ConnectionString = _connectionString;
                    dbConnecttion.Open();
                }

                return dbConnecttion;
            }
        }

    }
}